5장 리액트와 상태 관리 라이브러리
1. 상태 관리는 왜 필요한가?
UI
, URL
, FORM
, 서버에서 받은 데이터
등의 상태의 일관성을 유지하고 성능을 최적화 시켜 유지보수를 용이하게 만든다.
1. 리액트 상태 관리의 역사
1. Flux 패턴의 등장
웹 애플리케이션이 비대해지고 상태가 많아짐에 따라 상태의 추적이 어려워 데이터의 흐름을 단순화 시키기 위해 만들어졌다.
Action
→ Dispatcher
→ Model
→ View
의 단방향 데이터 흐름을 가진다.
2. 리덕스의 등장
하나의 상태 객체를 스토어에 저장해 두고, 이 객체를 업데이트하는 작업을 디스패치해 업데이트를 수행한다. proops
를 전역으로 관리해 하위 컴포넌트에 전파할 수 있다.
3. Context API와 useContext
proops
의 단순 상태 참조시 리덕스 사용 부담이 컸기 때문에 만들어졌다. Context
를 생성하고 훅을 사용해 호출한다.
4. 훅의 탄생, 그리고 React Query와 SWR
훅의 발전으로 함수 컴포넌트의 사용이 많아지게 되었고 상태 관리가 쉬워지게 되었다. 이에 따라 데이터를 불러오는데 특화된 라이브러리가 등장하게 된다.
import React from 'react'
import useSWR from 'swr'
const fetcher = (url) => fetch(url).then((res) => res.json())
export default function App() {
const { data, error } = useSWR(
'https://api.github.com/repos/vercel/swr',
fetcher,
)
if (error) return 'An error has occurred.'
if (!data) return 'Loading...'
return (
<div>
<p>{JSON.stringify(data)}</p>
</div>
)
}
2. 리액트 훅으로 시작하는 상태 관리
1. useSubscription
스토어를 생성 후 훅을 사용해 상태를 구독하고 상태가 변하면 UI를 업데이트 하는 방식이다.
// store.js
const store = {
state: { count: 0 },
listeners: new Set(),
setState(newState) {
this.state = { ...this.state, ...newState };
this.listeners.forEach(listener => listener(this.state));
},
subscribe(listener) {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
},
};
export default store;
// useSubscription.js
import { useState, useEffect } from "react";
import store from "./store";
const useSubscription = () => {
const [state, setState] = useState(store.state);
useEffect(() => {
const unsubscribe = store.subscribe(setState);
return () => unsubscribe();
}, []);
return state;
};
export default useSubscription;
import React from "react";
import { useSubscription } from "./useSubscription";
import store from "./store";
const Counter = () => {
const { count } = useSubscription();
const increment = () => {
store.setState({ count: count + 1 });
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
export default Counter;